//------------------------------------------------
// controller.v
//
// James Forrest, 2013
// Based on code by:
// David_Harris@hmc.edu 3 November 2005
//
// Pipelined MIPS processor
//------------------------------------------------

module controller(input        clk, reset,
                  input  [5:0] opD, functD,
                  input  [4:0] rsD,
                  input        stallE, stallM, flushE, flushM, flushW, compD,
                  output       memtoregE, memtoregM, memtoregW, cp0ToRegE, cp0ToRegW, memwriteD, memwriteM, memwriteW,
                  output       pcsrcD, branchD, alusrcAE, alusrcBE, 
                  output [1:0] regdstE,
                  output       regwriteD, regwriteE, regwriteM, regwriteW, linkE, signextD,
                  output [1:0] jumpD,
                  output [2:0] compcontrolD,
                  output [3:0] alucontrolE,

                  output       cp0WriteEnableW, eretM, overflowAbleM,
                  output       addressErrorOnLoadAbleM, addressErrorOnStoreAbleM,
                  output       badInstructionM
                  );

  wire       memwriteE, memtoregD, alusrcAD, alusrcBD, linkD;
  wire [1:0] regdstD;
  wire [2:0] aluopD;
  wire [3:0] alucontrolD;

  maindec md(opD, functD, rsD, memtoregD, memwriteD, branchD, compcontrolD,
             alusrcAD, alusrcBD, regdstD, regwriteD, linkD, jumpD,
             signextD, aluopD,
             cp0WriteEnableD, eretD, overflowAbleD,
             addressErrorOnLoadAbleD, addressErrorOnStoreAbleD,
             badInstructionD, cp0ToRegD);

  aludec  ad(functD, {signextD, aluopD}, alucontrolD);

  assign pcsrcD = branchD & compD;

  // pipeline registers
  flopenrc #(19) regE(clk, reset, ~stallE, flushE,
                      {memtoregD, memwriteD, alusrcAD, alusrcBD, regdstD, regwriteD, linkD, alucontrolD, cp0ToRegD,
                       cp0WriteEnableD, eretD, overflowAbleD, addressErrorOnLoadAbleD, addressErrorOnStoreAbleD, badInstructionD}, 
                      {memtoregE, memwriteE, alusrcAE, alusrcBE, regdstE, regwriteE, linkE, alucontrolE, cp0ToRegE,
                       cp0WriteEnableE, eretE, overflowAbleE, addressErrorOnLoadAbleE, addressErrorOnStoreAbleE, badInstructionE});
  flopenrc #(10) regM(clk, reset, ~stallM, flushM,
                      {memtoregE, memwriteE, regwriteE, cp0ToRegE,
                       cp0WriteEnableE, eretE, overflowAbleE, addressErrorOnLoadAbleE, addressErrorOnStoreAbleE, badInstructionE},
                      {memtoregM, memwriteM, regwriteM, cp0ToRegM,
                       cp0WriteEnableM, eretM, overflowAbleM, addressErrorOnLoadAbleM, addressErrorOnStoreAbleM, badInstructionM});
  floprc   #(5)  regW(clk, reset, flushW,
                      {memtoregM, regwriteM, cp0WriteEnableM, cp0ToRegM, memwriteM},
                      {memtoregW, regwriteW, cp0WriteEnableW, cp0ToRegW, memwriteW});
endmodule
